from datetime import date, timedelta,datetime
from app.models import Task, Content, ReviewPlan, PlanConfig,StudyRecord
from sqlalchemy import func, extract, case,text
from app.extensions import db
from app.services.review_plan_service import ReviewPlanService
# 艾宾浩斯间隔天数配置
EBBINGHAUS_INTERVALS = [1, 2, 4, 7, 15,30]
class TaskService:
    """任务管理服务"""
    @staticmethod
    def update_task_byKnow(task_id, next_review_date, student_id, content_id):
        # 1. 更新指定任务的状态和属性
        task = Task.query.filter_by(
            task_id=task_id,
            student_id=student_id,
            content_id=content_id
        ).first()

        if task:
            # 更新任务属性
            task.task_type = '复习'  # 将任务类型改为复习
            task.plan_date = next_review_date  # 更新计划日期
            task.status = True  # 标记为已完成
            
            # 处理review_stage
            if task.review_stage is None:
                task.review_stage = 0
            else:
                task.review_stage += 1
            
            db.session.commit()
            return True
        else:
            return False
        

    @staticmethod
    def generate_daily_tasks(student_id):
        # 处理配置不存在的情况
        try:
            config = PlanConfig.query.filter_by(student_id=student_id).first()
            if not config:
                return {
                    'code': 404,
                    'msg': '学习计划未配置',
                    'data': [],
                    'daily_new': 0,
                    'daily_review': 0,
                    'max_repeat': 0
                }
            
            daily_new = config.daily_new
            daily_review = config.daily_review
            max_repeat = config.max_repeat

            today = datetime.now().strftime('%Y-%m-%d')

            # 查询今日的新任务（未完成的每日任务）
            new_tasks = Task.query.filter(
                Task.student_id == student_id,
                Task.plan_date <= today,  # 计划日期小于等于今天
                Task.task_type == '每日',
                Task.status == False
            ).limit(daily_new).all()

            # 统一返回结构
            base_result = {
                'daily_new': daily_new,
                'daily_review': daily_review,
                'max_repeat': max_repeat,
                'code': 200,
                'msg': 'success',
                'data': []
            }

            if not new_tasks:
                # 如果没有新任务，查询今日的复习任务
                review_candidates = Task.query.filter(
                    Task.student_id == student_id,
                    Task.plan_date == today,  # 只查询今天的复习任务
                    Task.task_type == '复习',
                    Task.status == False
                ).limit(daily_new + daily_review).all()
                
                if not review_candidates:
                    return base_result
                
                contents = []
                for task in review_candidates:
                    content = Content.query.filter_by(content_id=task.content_id).first()
                    if not content:
                        continue
                    
                    contents.append({
                        "content_id": content.content_id,
                        "type": content.type,
                        "title": content.title,
                        'text': content.text,
                        'pinyin': content.pinyin,
                        'translation': content.translation,
                        "task_id": task.task_id,
                        'max_repeat': max_repeat
                    })
                
                base_result['data'] = contents
                return base_result

            else:
                # 如果有新任务，查询今日的复习任务
                review_tasks = Task.query.filter(
                    Task.student_id == student_id,
                    Task.plan_date == today,  # 只查询今天的复习任务
                    Task.task_type == '复习',
                    Task.status == False
                ).limit(daily_review).all()
                
                tasks = new_tasks + review_tasks
                contents = []
                for task in tasks:
                    content = Content.query.filter_by(content_id=task.content_id).first()
                    if not content:
                        continue
                    
                    contents.append({
                        "content_id": content.content_id,
                        "type": content.type,
                        "title": content.title,
                        'text': content.text,
                        'pinyin': content.pinyin,
                        'translation': content.translation,
                        "task_id": task.task_id,
                        'max_repeat': max_repeat
                    })
                
                base_result['data'] = contents
                return base_result

        except Exception as e:
            return {
                'code': 500,
                'msg': f'服务器错误: {str(e)}',
                'data': [],
                'daily_new': 0,
                'daily_review': 0,
                'max_repeat': 0
            }
    
            
        
        

    # @staticmethod
    # def generate_daily_tasks(student_id: int, plan_date: date) -> dict:
    #     """生成每日学习任务（新任务 + 复习任务）"""
    #     # 获取学习计划配置
    #     config = PlanConfig.query.filter_by(student_id=student_id).first()
    #     if not config:
    #         return {'code': 404, 'msg': '未找到学习计划配置'}
        
    #     # 生成新任务
    #     new_tasks = TaskService._generate_new_tasks(student_id, plan_date, config.daily_new)
    #     # 生成复习任务
    #     review_tasks = TaskService._generate_review_tasks(student_id, plan_date, config.daily_review, config.max_repeat)
        
    #     # 合并任务
    #     tasks = new_tasks + review_tasks
    #     db.session.bulk_save_objects(tasks)
    #     db.session.commit()
    #     return {'code': 200, 'msg': f'已生成{len(tasks)}条任务'}

    # @staticmethod
    # def _generate_new_tasks(student_id: int, plan_date: date, daily_new: int) -> list:
    #     """生成每日新任务"""
    #     # 获取最新的未学习内容
    #     contents = Content.query.filter(
    #         ~Content.content_id.in_(
    #             db.session.query(Task.content_id)
    #             .filter(Task.student_id == student_id)
    #         )
    #     ).order_by(Content.create_time.desc()).limit(daily_new).all()

    #     return [
    #         Task(
    #             plan_date=plan_date,
    #             task_type='每日',
    #             status=False,
    #             review_stage=0,
    #             student_id=student_id,
    #             content_id=content.content_id
    #         ) for content in contents
    #     ]

    # @staticmethod
    # def _generate_review_tasks(student_id: int, plan_date: date, daily_review: int, max_repeat: int) -> list:
    #     """生成复习任务"""
    #     # 获取需要复习的计划
    #     review_plans = ReviewPlan.query.filter(
    #         ReviewPlan.student_id == student_id,
    #         ReviewPlan.next_review_date <= plan_date,
    #         ReviewPlan.ebbinghaus_stage < max_repeat
    #     ).order_by(ReviewPlan.next_review_date.asc()).limit(daily_review).all()

    #     # 更新复习计划的下次日期
    #     for plan in review_plans:
    #         plan.ebbinghaus_stage += 1
    #         plan.next_review_date = plan_date + timedelta(days=ReviewPlanService.EBBINGHAUS_INTERVALS[plan.ebbinghaus_stage])
        
    #     return [
    #         Task(
    #             plan_date=plan_date,
    #             task_type='复习',
    #             status=False,
    #             review_stage=plan.ebbinghaus_stage,
    #             student_id=student_id,
    #             content_id=plan.content_id
    #         ) for plan in review_plans
    #     ]
    
    @staticmethod
    def get_tasks(student_id):
        try:
            tasks = Task.query.filter_by(student_id=student_id).all()
            # 构建返回数据
            result = {
                'code': 200,
                'msg': '获取成功',
                'data': []
            }
            # print('=====================tasks=================')
            # print(tasks)
            # print('====================tasks==================')
            for task in tasks:
                # 使用 .first() 查询单条记录
                content = Content.query.filter_by(content_id=task.content_id).first()
                # print('====================content==================')
                # print(content)
                # print('====================content==================')
                if content:
                    task_dict = task.to_dict()
                    task_dict['title'] = content.title
                    result['data'].append(task_dict)
            
            return result
        except Exception as e:
            print(e)
            return {
                'code': 500,
                'msg': '服务器内部错误',
                'data': []
            }
        
    @staticmethod
    def delete_task(task_id):
        print('delete task：',task_id)
        try:
            task = Task.query.filter_by(task_id=task_id).first()
            if task:
                db.session.delete(task)
                db.session.commit()
                return {
                    'code': 200,
                    'msg': '删除成功',
                }
            else:
                return {
                    'code': 404,
                    'msg': '任务不存在',
                }

        except Exception as e:
            db.session.rollback()
            return {
                'code': 500,
                'msg': '删除失败',
            }
    
    @staticmethod
    def update_task(task_id):
        # 如果是1改为0，是0就改为1
        try:
            task = Task.query.filter_by(task_id=task_id).first()
            if task:
                task.status = 1 if task.status == 0 else 0
                db.session.commit()
                return {
                    'code': 200,
                    'msg': '更新成功',
                }
            else:
                return {
                    'code': 404,
                   'msg': '任务不存在',
                }
        except Exception as e:
            db.session.rollback()
            return {
                'code': 500,
                'msg': '更新失败',
            }
        

    @staticmethod
    def get_daily_report(student_id):
        end_date = date.today()
        start_date = end_date - timedelta(days=99)

        results = db.session.query(
            Task.plan_date.label('date'),
            func.count().label('total'),
            # 关键修正：明确统计 status=1 的任务数
            func.sum(
                case((Task.status == 1, 1), else_=0)
            ).label('completed'),
            # 完成率计算（带除零保护）
            func.coalesce(
                func.sum(case((Task.status == 1, 1.0), else_=0.0)) * 100.0 / 
                func.nullif(func.count(), 0), 
                0.0
            ).label('rate')
        ).filter(
            Task.student_id == student_id,
            Task.plan_date.between(start_date, end_date)
        ).group_by(
            Task.plan_date
        ).order_by(
            Task.plan_date
        ).all()

        return {
            "code": 200,
            "data": [{
                "date": r.date.strftime('%Y-%m-%d'),
                "total": int(r.total),
                "completed": int(r.completed),
                "rate": round(float(r.rate), 2)
            } for r in results]
        }


    @staticmethod
    def get_weekly_report(student_id):
        try:
            end_date = date.today()
            start_date = end_date - timedelta(weeks=99)  
            results = db.session.query(
                extract('year', Task.plan_date).label('year'),
                extract('week', Task.plan_date).label('week'),
                func.min(Task.plan_date).label('start_date'),
                func.max(Task.plan_date).label('end_date'),
                func.count().label('total'),
                # 关键修正：明确统计已完成任务数（避免status类型问题）
                func.sum(case((Task.status == 1, 1), else_=0)).label('completed'),
                # 完成率计算（带除零保护）
                func.coalesce(
                    func.sum(case((Task.status == 1, 1.0), else_=0.0)) * 100.0 / 
                    func.nullif(func.count(), 0),
                    0.0
                ).label('rate')
            ).filter(
                Task.student_id == student_id,
                Task.plan_date.between(start_date, end_date)  # 明确时间范围
            ).group_by(
                'year', 'week'
            ).order_by(
                'year', 'week'
            ).all()

            return {
                "code": 200,
                "data": [{
                    "week": f"{int(r.year)}年第{int(r.week)}周",
                    "start_date": r.start_date.strftime('%Y-%m-%d'),
                    "end_date": r.end_date.strftime('%Y-%m-%d'),
                    "total": int(r.total),
                    "completed": int(r.completed),
                    "rate": round(float(r.rate), 2)  # 强制保留2位小数
                } for r in results]
            }
        except Exception as e:
            return {
                "code": 500,
                "error": str(e),
                "data": []
            }
    @staticmethod
    def get_forgetting_curve(student_id):
        """获取遗忘曲线数据（第0天强制100%）
        Args:
            student_id: 学生ID
        Returns:
            {
                "code": 200,
                "data": [
                    {
                        "days_interval": int,      # 间隔天数(0-15)
                        "time_label": str,         # 时间标签（今天/明天/N天后）
                        "theoretical_rate": float, # 理论记忆率(%)
                        "actual_rate": float|null, # 实际记忆率(%)
                        "review_count": int        # 复习次数
                    },
                    ...
                ]
            }
        """
        try:
            # 使用参数化查询防止SQL注入
            sql = """
            WITH 
            -- 时间标签映射
            day_labels(days_interval, time_label) AS (
                SELECT 0, '今天' UNION ALL SELECT 1, '明天' UNION ALL 
                SELECT 2, '后天' UNION ALL SELECT 3, '3天后' UNION ALL
                SELECT 4, '4天后' UNION ALL SELECT 5, '5天后' UNION ALL
                SELECT 6, '6天后' UNION ALL SELECT 7, '7天后' UNION ALL
                SELECT 8, '8天后' UNION ALL SELECT 9, '9天后' UNION ALL
                SELECT 10, '10天后' UNION ALL SELECT 11, '11天后' UNION ALL
                SELECT 12, '12天后' UNION ALL SELECT 13, '13天后' UNION ALL
                SELECT 14, '14天后' UNION ALL SELECT 15, '15天后'
            ),
            -- 艾宾浩斯理论曲线（第0天设为100%）
            theoretical_curve AS (
                SELECT 
                    dl.days_interval,
                    dl.time_label,
                    CASE 
                        WHEN dl.days_interval = 0 THEN 100.0
                        WHEN dl.days_interval = 1 THEN 33.7
                        WHEN dl.days_interval = 2 THEN 27.8
                        WHEN dl.days_interval = 3 THEN 26.6
                        WHEN dl.days_interval = 4 THEN 25.4
                        WHEN dl.days_interval = 5 THEN 24.2
                        WHEN dl.days_interval = 6 THEN 23.0
                        WHEN dl.days_interval = 7 THEN 22.2
                        WHEN dl.days_interval = 8 THEN 22.0
                        WHEN dl.days_interval = 9 THEN 21.8
                        WHEN dl.days_interval = 10 THEN 21.6
                        WHEN dl.days_interval = 11 THEN 21.4
                        WHEN dl.days_interval = 12 THEN 21.2
                        WHEN dl.days_interval = 13 THEN 21.0
                        WHEN dl.days_interval = 14 THEN 20.8
                        WHEN dl.days_interval = 15 THEN 20.6
                    END AS theoretical_rate
                FROM day_labels dl
            ),
            -- 实际复习数据统计（包含第0天）
            actual_review AS (
                SELECT 
                    DATEDIFF(t_review.plan_date, t_learn.plan_date) AS days_interval,
                    COUNT(*) AS total_reviews,
                    ROUND(SUM(CASE WHEN t_review.status = 1 THEN 1 ELSE 0 END) * 100.0 / 
                        NULLIF(COUNT(*), 0), 2) AS actual_rate
                FROM task t_review
                JOIN task t_learn ON t_review.content_id = t_learn.content_id
                    AND t_learn.task_type = '每日'
                    AND t_learn.student_id = :student_id
                WHERE t_review.task_type = '复习'
                AND t_review.student_id = :student_id
                AND t_review.plan_date BETWEEN DATE_SUB(NOW(), INTERVAL 100 DAY) AND NOW()
                GROUP BY days_interval
                HAVING days_interval BETWEEN 0 AND 15
            )
            -- 合并结果（第0天实际数据强制设为100%）
            SELECT 
                tc.days_interval,
                tc.time_label,
                tc.theoretical_rate,
                CASE 
                    WHEN tc.days_interval = 0 THEN 100.0
                    ELSE ar.actual_rate 
                END AS actual_rate,
                COALESCE(ar.total_reviews, 0) AS review_count
            FROM theoretical_curve tc
            LEFT JOIN actual_review ar ON tc.days_interval = ar.days_interval
            ORDER BY tc.days_interval;
            """

            # 执行查询
            results = db.session.execute(text(sql), {'student_id': student_id})
            
            # 格式化结果
            formatted_data = []
            for row in results:
                formatted_data.append({
                    "days_interval": row.days_interval,
                    "time_label": row.time_label,
                    "theoretical_rate": float(row.theoretical_rate),
                    "actual_rate": float(row.actual_rate) if row.actual_rate is not None else None,
                    "review_count": int(row.review_count)
                })

            return {"code": 200, "data": formatted_data}

        except Exception as e:
            import traceback
            traceback.print_exc()
            return {
                "code": 500,
                "error": f"查询失败: {str(e)}",
                "data": []
            }